<script lang="ts">
	import DanceTransition from "@/components/dance/dance-transition.svelte"
	import { i18n } from "@/i18n"
	import { appConfig, appState, winExtMap } from "@/stores"
	import { helperAPI } from "@/utils/helper"
	import { paste } from "@/utils/hotkey"
	import { goBackOnEscape } from "@/utils/key"
	import { decideKkrpcSerialization } from "@/utils/kkrpc"
	import { goHome } from "@/utils/route"
	import { positionToCssStyleString, positionToTailwindClasses } from "@/utils/style"
	import { sleep } from "@/utils/time"
	import { isInMainWindow } from "@/utils/window"
	import { CustomPosition, ThemeColor, type Position } from "@kksh/api/models"
	import {
		constructJarvisServerAPIWithPermissions,
		// exposeApiToWindow,
		type IApp,
		type IUiCustom
	} from "@kksh/api/ui"
	import { toast, type IUiCustomServer1, type IUiCustomServer2 } from "@kksh/api/ui/custom"
	import { db } from "@kksh/drizzle"
	import { Button } from "@kksh/svelte5"
	import { cn } from "@kksh/ui/utils"
	import type { IKunkunFullServerAPI } from "@kunkunapi/src/api/server"
	import {
		RECORD_EXTENSION_PROCESS_EVENT,
		type IRecordExtensionProcessEvent
	} from "@kunkunapi/src/events"
	import { emitTo } from "@tauri-apps/api/event"
	import { getCurrentWindow } from "@tauri-apps/api/window"
	import { info } from "@tauri-apps/plugin-log"
	import { goto } from "$app/navigation"
	import { IframeParentIO, RPCChannel } from "kkrpc/browser"
	import { ArrowLeftIcon, MoveIcon, RefreshCcwIcon, XIcon } from "lucide-svelte"
	import { onDestroy, onMount } from "svelte"
	import type { PageData } from "./$types"

	let { data }: { data: PageData } = $props()
	const { loadedExt, url, extPath, extInfoInDB } = data
	let extSpawnedProcesses = $state<number[]>([])
	let iframeRef: HTMLIFrameElement
	let uiControl = $state<{
		iframeLoaded: boolean
		showBackBtn: boolean
		showMoveBtn: boolean
		showRefreshBtn: boolean
		backBtnPosition: Position
		moveBtnPosition: Position
		refreshBtnPosition: Position
		transparentBg: boolean
	}>({
		iframeLoaded: false,
		showBackBtn: true, // if open in new window, hide back button
		showMoveBtn: true,
		showRefreshBtn: true,
		backBtnPosition: "top-left",
		moveBtnPosition: "bottom-left",
		refreshBtnPosition: "top-right",
		transparentBg: false
	})

	const iframeUiAPI: IUiCustomServer2 = {
		goBack: async () => {
			if (isInMainWindow()) {
				goto(i18n.resolveRoute("/app/"))
			} else {
				data.win?.close()
			}
		},
		hideBackButton: async () => {
			uiControl.showBackBtn = false
		},
		hideMoveButton: async () => {
			uiControl.showMoveBtn = false
		},
		hideRefreshButton: async () => {
			console.log("hideRefreshButton")
			uiControl.showRefreshBtn = false
		},
		showBackButton: async (position?: Position) => {
			console.log("showBackBtn", position)

			uiControl.showBackBtn = true
			uiControl.backBtnPosition = position ?? "top-left"
		},
		showMoveButton: async (position?: Position) => {
			uiControl.showMoveBtn = true
			uiControl.moveBtnPosition = position ?? "bottom-left"
		},
		showRefreshButton: async (position?: Position) => {
			uiControl.showRefreshBtn = true
			uiControl.refreshBtnPosition = position ?? "top-right"
		},
		getTheme: () => {
			const theme = $appConfig.theme
			return Promise.resolve({
				theme: theme.theme as ThemeColor,
				radius: theme.radius,
				lightMode: theme.lightMode
			})
		},
		async reloadPage() {
			location.reload()
		},
		async setTransparentWindowBackground(transparent: boolean) {
			if (isInMainWindow()) {
				throw new Error("Cannot set background in main window")
			}
			if (transparent) {
				document.body.style.backgroundColor = "transparent"
			} else {
				document.body.style.backgroundColor = ""
			}
		}
	}

	const serverAPI: IKunkunFullServerAPI = constructJarvisServerAPIWithPermissions(
		loadedExt.kunkun.permissions,
		loadedExt.extPath,
		{
			recordSpawnedProcess: async (pid: number) => {
				extSpawnedProcesses = [...extSpawnedProcesses, pid]
				// winExtMap.registerProcess(appWin.label, pid)
				const curWin = await getCurrentWindow()
				await emitTo("main", RECORD_EXTENSION_PROCESS_EVENT, {
					windowLabel: curWin.label,
					pid
				} satisfies IRecordExtensionProcessEvent)
				// TODO: record process in a store
			},
			getSpawnedProcesses: () => Promise.resolve(extSpawnedProcesses),
			paste: async () => {
				await data.win?.hide()
				await sleep(200)
				return paste()
			}
		}
	)
	const serverAPI2 = {
		...serverAPI,
		iframeUi: {
			...serverAPI.iframeUi,
			...iframeUiAPI
		} satisfies IUiCustomServer1 & IUiCustomServer2,
		helper: helperAPI,
		db: new db.JarvisExtDB(extInfoInDB.extId),
		kv: new db.KV(extInfoInDB.extId),
		app: {
			language: () => Promise.resolve("en") // TODO: get locale
		} satisfies IApp
	}

	function onBackBtnClicked() {
		if (isInMainWindow()) {
			goHome()
		} else {
			data.win?.close()
		}
	}

	function onIframeLoaded() {
		setTimeout(() => {
			iframeRef.focus()
			uiControl.iframeLoaded = true
			appState.setFullScreenLoading(false)
		}, 300)
	}

	onMount(() => {
		appState.setFullScreenLoading(true)
		setTimeout(() => {
			data.win?.setFocus()
		}, 200)
		if (iframeRef?.contentWindow) {
			const io = new IframeParentIO(iframeRef.contentWindow)
			const kkrpcSerialization = decideKkrpcSerialization(loadedExt)
			info(
				`Establishing kkrpc connection for ${loadedExt.kunkun.identifier} with serialization: ${kkrpcSerialization}`
			)
			const rpc = new RPCChannel(io, {
				expose: serverAPI2,
				serialization: {
					version: kkrpcSerialization
				}
			})
		} else {
			toast.warning("iframeRef.contentWindow not available")
		}

		setTimeout(() => {
			if (!uiControl.iframeLoaded) {
				toast.error("Extension failed to load")
			}
		}, 3_000)
	})

	onDestroy(() => {
		winExtMap.unregisterExtensionFromWindow(data.win?.label ?? "")
	})
</script>

<svelte:window on:keydown={goBackOnEscape} />
{#if uiControl.backBtnPosition && uiControl.showBackBtn}
	<Button
		class={cn("absolute", positionToTailwindClasses(uiControl.backBtnPosition))}
		size="icon"
		variant="outline"
		onclick={onBackBtnClicked}
		style={`${positionToCssStyleString(uiControl.backBtnPosition)}`}
	>
		{#if data.win?.label === "main"}
			<ArrowLeftIcon class="w-4" />
		{:else}
			<XIcon class="w-4" />
		{/if}
	</Button>
{/if}
{#if uiControl.moveBtnPosition && uiControl.showMoveBtn}
	<Button
		class={cn("absolute", positionToTailwindClasses(uiControl.moveBtnPosition))}
		style={`${positionToCssStyleString(uiControl.moveBtnPosition)}`}
		size="icon"
		variant="outline"
		data-tauri-drag-region
	>
		<MoveIcon data-tauri-drag-region class="w-4" />
	</Button>
{/if}
{#if uiControl.refreshBtnPosition && uiControl.showRefreshBtn}
	<Button
		class={cn("absolute", positionToTailwindClasses(uiControl.refreshBtnPosition))}
		style={`${positionToCssStyleString(uiControl.refreshBtnPosition)}`}
		size="icon"
		variant="outline"
		onclick={iframeUiAPI.reloadPage}
	>
		<RefreshCcwIcon class="w-4" />
	</Button>
{/if}

<main class="h-screen">
	<iframe
		bind:this={iframeRef}
		class={cn("h-full", {
			hidden: !uiControl.iframeLoaded
		})}
		onload={onIframeLoaded}
		width="100%"
		height="100%"
		frameborder="0"
		src={data.url}
		title={data.extPath}
	></iframe>
</main>
